package groupb6.shopsystem.messaging.group;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import groupb6.shopsystem.mapper.MessageMapper;
import groupb6.shopsystem.mapper.UserMapper;
import groupb6.shopsystem.messaging.entity.Key;
import groupb6.shopsystem.messaging.entity.Notice;
import groupb6.shopsystem.messaging.entity.WebSocketGroup;
import groupb6.shopsystem.messaging.server.WebsocketServer;
import groupb6.shopsystem.pojo.entity.Message;
import groupb6.shopsystem.pojo.entity.User;
import groupb6.shopsystem.util.JWTUtil;
import groupb6.shopsystem.util.enums.IdentityEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.websocket.Session;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Component
@Slf4j
public class WSGroupService {

    @Autowired
    private MessageMapper messageMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WebsocketServer websocketServer;


    /*
     * 打开链接
     * */
    @Transactional
    public void open(Session session) {
        //获取群组
        List<Integer> params = getSessionParams(session);
        User currentUser = JWTUtil.getCurrentUserWS(session);
        User customer = userMapper.selectById(params.get(1));
        User seller = userMapper.selectById(params.get(0));
        if (!Objects.equals(currentUser.getId(), customer.getId())
                && !Objects.equals(currentUser.getId(), seller.getId())) {
            log.error("当前token无法认证为该群组人员");
            throw new RuntimeException("当前token无法认证为该群组人员");

        }

        Key key = new Key(seller, customer);
        if (!WebsocketServer.getChattingMap().containsKey(key.getKey())) {
            //创建群组
            WebSocketGroup webSocketGroup = createGroup(seller, customer, key);
            WebsocketServer.getChattingMap().put(key.getKey(), webSocketGroup);
        }
        WebSocketGroup webSocketGroup = WebsocketServer.getChattingMap().get(key.getKey());
        //加入群组
        webSocketGroup.addUser(currentUser, session);
        //向全部用户发送加入连接的通知
        webSocketGroup.postStatusAll(currentUser.getName() + " 已经加入连接");
        //向接入用户推送全部聊天记录
        webSocketGroup.loadMessage(currentUser);

        log.info(currentUser.getName() + "加入群组成功，key=" + webSocketGroup.getKey().getKey());
    }

    /*
     * 聊天群族发送消息
     * */
    public void message(Session session, String message) {

        User currentUser = JWTUtil.getCurrentUserWS(session);

        List<Integer> params = getSessionParams(session);
        User customer = userMapper.selectById(params.get(1));
        User seller = userMapper.selectById(params.get(0));
        Key key = new Key(seller, customer);
        //获取群组
        WebSocketGroup webSocketGroup = WebsocketServer.getChattingMap().get(key.getKey());
        User receiver;
        Message messageEntity = new Message();
        messageEntity.setMessage(message);
        //TODO:如何加入客服的消息记录？是否需要重构数据结构
        messageEntity.setTime(Timestamp.valueOf(LocalDateTime.now()));
        messageEntity.setSendId(currentUser.getId());
        if (currentUser.getId().equals(seller.getId())
                && currentUser.getIdentity().equals(IdentityEnum.SELLER.getIdentity())) {
            receiver=customer;
            messageEntity.setReceiveId(customer.getId());
        } else if (currentUser.getId().equals(customer.getId())
                && currentUser.getIdentity().equals(IdentityEnum.BUYER.getIdentity())) {
            receiver=seller;
            messageEntity.setReceiveId(seller.getId());
        } else {
            throw new RuntimeException("消息发送校验失败:当前用户身份不符");
        }

        webSocketGroup.postMessageAll(messageEntity);
        webSocketGroup.getNewMessages().add(messageEntity);
        //如果对方没在线则发送消息通知
        if(!webSocketGroup.getSessionMap().containsKey(messageEntity.getReceiveId())){
            Notice notice=new Notice();
            notice.setSenderId(currentUser.getId());
            if(Objects.equals(currentUser.getId(), customer.getId())){
                notice.setReceiverId(seller.getId());
            }
            else if(Objects.equals(currentUser.getId(), seller.getId())){
                notice.setReceiverId(customer.getId());
            }

            notice.setContent("senderId="+notice.getSenderId()+",receiver=你 的群组有新消息");
            WebsocketServer.addNotice(notice,receiver.getId());
        }
        log.info("发送新消息成功,User:" + currentUser.getName() + ",message:" + message);
    }

    /*
     * 关闭连接
     * */
    @Transactional
    public void close(Session session) {
        List<Integer> params = getSessionParams(session);
        User currentUser = JWTUtil.getCurrentUserWS(session);
        User customer = userMapper.selectById(params.get(1));
        User seller = userMapper.selectById(params.get(0));
        Key key = new Key(seller, customer);
        //获取群组
        WebSocketGroup webSocketGroup = WebsocketServer.getChattingMap().get(key.getKey());
        //退出群组
        webSocketGroup.exitUser(currentUser, session);
        log.info(currentUser + "退出群组成功。");
        if (webSocketGroup.getOnlineNum().intValue() == 0) {
            //删除群组
            destroyGroup(webSocketGroup);
            WebsocketServer.getChattingMap().remove(key.getKey());
        } else {
            webSocketGroup.postStatusAll(currentUser.getName() + " 已经退出连接");
        }
    }
    /*
     * 报告错误
     * */

    public void error(Session session, Throwable e) {
        List<Integer> params = getSessionParams(session);
        User currentUser = JWTUtil.getCurrentUserWS(session);
        User customer = userMapper.selectById(params.get(1));
        User seller = userMapper.selectById(params.get(0));
        Key key = new Key(seller, customer);
        //获取群组
        WebSocketGroup webSocketGroup = WebsocketServer.getChattingMap().get(key.getKey());
        webSocketGroup.postStatus(currentUser, e.getMessage());
        webSocketGroup.postStatus(currentUser, "发生错误，连接关闭。");
    }

    /*
     * 聊天群组初始化
     * */
    private WebSocketGroup createGroup(User seller, User customer, Key key) {

        if (!Objects.equals(seller.getIdentity(), IdentityEnum.SELLER.getIdentity()) ||
                !Objects.equals(customer.getIdentity(), IdentityEnum.BUYER.getIdentity())) {
            throw new RuntimeException("聊天群组初始化失败：用户身份错误");
        }
        WebSocketGroup webSocketGroup = new WebSocketGroup();
        webSocketGroup.setCustomer(customer);
        webSocketGroup.setSeller(seller);
        webSocketGroup.setKey(key);
        LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Message::getSendId, seller.getId())
                .eq(Message::getReceiveId, customer.getId())
                .or()
                .eq(Message::getSendId, customer.getId())
                .eq(Message::getReceiveId, seller.getId())
                .orderByAsc(Message::getTime);
        webSocketGroup.setHistoryMessages(messageMapper.selectList(wrapper));
        webSocketGroup.setNewMessages(new ArrayList<>());
        log.info("创建群组成功，key=" + webSocketGroup.getKey());
        return webSocketGroup;
    }

    /*
     * 聊天群组关闭，保存聊天记录
     * */

    private void destroyGroup(WebSocketGroup webSocketGroup) {
        List<Message> messages = webSocketGroup.getNewMessages();
        //TODO:优化循环插入
        for (Message message : messages) {
            messageMapper.insert(message);
        }
        log.info("群组注销成功");
    }

    private List<Integer> getSessionParams(Session session) {
        Integer customerId;
        Integer sellerId;
        String token;
        Map<String, List<String>> queryParams = session.getRequestParameterMap();
        customerId = Integer.parseInt(queryParams.get("customerId").get(0));
        sellerId = Integer.parseInt(queryParams.get("sellerId").get(0));
        token = queryParams.get("token").get(0);
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(sellerId);
        arrayList.add(customerId);
        return arrayList;
    }

}
